#include "../head.h"

/*
TCP 的通信过程
    服务器：创建套接字 绑定ip地址和端口 设置监听 阻塞等待客户端连接 接收数据 关闭套接字
    客户端：创建套接字 绑定ip地址和端口 连接服务器 发送数据 关闭套接字
创建套接字 返回 套接字文件描述符sockfd
int socket(int domain, int type, int protocol);
    domain 网络协议 AF_INET->ipv4  AF_INET6->ipv6
    type 传输协议 SOCK_STREAM->TCP  SOCK_DGRAM->UDP
    protocol 协议 默认使用0
绑定ip地址和端口号  返回 0 成功 -1 失败
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
    sockfd 套接字文件描述符
    addr 结构体sockaddr的指针 用来保存ip地址和端口号
    addrlen sockaddr结构体的大小
设置监听 返回 0 成功 -1 失败
int listen(int sockfd, int backlog);
    sockfd 套接字文件描述符
    backlog 表示最多同时连接的客户端数量
等待接受客户端连接 阻塞 返回套接字文件描述符
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
    sockfd 套接字文件描述符
    addr 连接上来的1客户端的ip地址和端口号
    addrlen 结构体大小
接收数据
ssize_t recv(int sockfd, void *buf, size_t len, int flags);
    sockfd 套接字文件描述符
    buf 接收数据
    len 接收数据的最大长度
    flags 标志位 一般设置为0
*/

int main()
{
    printf("服务器启动\n");
    // 1.创建套接字
    int sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd < 0)
    {
        printf("socket error\n");
        return -1;
    }
    // 2.创建结构体
    struct sockaddr_in server_addr;
    memset(&server_addr, 0, sizeof(server_addr));
    server_addr.sin_family = AF_INET;                          // 使用ipv4
    server_addr.sin_port = htons(6153);                        // 端口号 htons() 主机字节序转网络字节序（大端序） ntohs() 网络字节序转主机字节序
    server_addr.sin_addr.s_addr = inet_addr("192.168.47.198"); // ip地址 inet_addr() 主机ip转网络ip  inet_ntoa() 网络ip转主机ip
    // 3.绑定ip地址和端口
    int bind_res = bind(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr));
    if (bind_res < 0)
    {
        printf("bind error\n");
        return -1;
    }
    // 4.设置监听
    int listen_res = listen(sockfd, 5);
    if (listen_res < 0)
    {
        printf("listen error\n");
        return -1;
    }
    while (1)
    {
        // 创建Client端地址结构体
        struct sockaddr_in client_addr;
        memset(&client_addr, 0, sizeof(client_addr));
        // 5.接受客户端的连接  返回已连接的套接字文件描述符
        int Client_len = sizeof(client_addr);
        int connectfd = accept(sockfd, (struct sockaddr *)&client_addr, &Client_len);
        if (connectfd < 0)
        {
            printf("accept error\n");
            continue;
        }
        printf("client ip: %s, port: %d\n", inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));
        while (1)
        {
            // 6.接收数据
            char buf[1024] = {0};
            ssize_t recv_res = recv(connectfd, buf, sizeof(buf), 0);
            if (recv_res < 0)
            {
                printf("接收失败\n");
                continue;
            }
            else if (recv_res == 0)
            {
                printf("客户端断开连接\n");
                break;
            }
            printf("接收到的数据：%s\n", buf);
        }
        // 7.关闭套接字
        close(connectfd);
        printf("服务器关闭connectfd\n");
    }

    close(sockfd);
    return 0;
}